#pragma once

#include"Log.hpp"

#include<sys/types.h>
#include<sys/socket.h>
#include<string>
#include<vector>
#include<cerrno>
#include<cstring>

namespace bobo
{
    // 1. 报文和报文之间，我们采用特殊字符来进行解决粘报问题
    // 2. 获取一个一个独立完整的报文，序列和反序列化 -- 自定义
    // 100+19X100+19X100+19

    // 支持解决粘报问题，处理独立报文
    #define SPACE " "
    #define SPACE_LEN strlen(SPACE)
    #define SEP "X"
    #define SEP_LEN strlen(SEP)
    // 我们要把传入进来的缓冲区进行切分
    // 1. buffer被切走的，也同时要从buffer中移除
    // 2. 可能会存在多个报文，多个报文依次放入out
    // buffer: 输入输出型参数
    // out: 输出型参数
    void SplitMessage(std::string& buffer, std::vector<std::string>* out)
    {
        while(true)
        {
            auto pos = buffer.find(SEP);
            if(pos == std::string::npos) break;
            std::string package = buffer.substr(0, pos);
            buffer.erase(0, pos + SEP_LEN);
            out->push_back(package);
        }
    }
    void Encode(std::string& s)
    {
        s += 'X';
    }
    class Request
    {
    public:
        Request(int x = 0, int y = 0, char op = '+')
            :_x(x)
            ,_y(y)
            ,_op(op)
        {}
        std::string Serialize()
        {
            std::string str;
            str = std::to_string(_x);
            str += SPACE;
            str += _op; // TODO
            str += SPACE;
            str += std::to_string(_y);
            return str;
        }
        bool Deserialize(const std::string& str)
        {
            std::size_t left = str.find(SPACE);
            if (left == std::string::npos)
                return false;
            std::size_t right = str.rfind(SPACE);
            if (right == std::string::npos)
                return false;
            _x = atoi(str.substr(0, left).c_str());
            _y = atoi(str.substr(right + SPACE_LEN).c_str());
            if (left + SPACE_LEN > str.size())
                return false;
            else
                _op = str[left + SPACE_LEN];
            return true;
        }
    public:
        int _x;
        int _y;
        char _op;
    };

    class Response
    {
    public:
        Response(int result = 0, int code = 0)
            :_result(result)
            ,_code(code)
        {}
        std::string Serialize()
        {
            std::string s;
            s = std::to_string(_code);
            s += SPACE;
            s += std::to_string(_result);
            return s;
        }
        bool Deserialize(const std::string& s)
        {
            std::size_t pos = s.find(SPACE);
            if (pos == std::string::npos)
                return false;
            _code = atoi(s.substr(0, pos).c_str());
            _result = atoi(s.substr(pos + SPACE_LEN).c_str());
            return true;
        }
    public:
        int _result;
        int _code;
    };
}